// Copyright 2010 Christophe Henry
// henry UNDERSCORE christophe AT hotmail DOT com
// This is an extended version of the state machine available in the boost::mpl library
// Distributed under the same license as the original.
// Copyright for the original version:
// Copyright 2005 David Abrahams and Aleksey Gurtovoy. Distributed
// under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

#include <boost/msm/back/state_machine.hpp>
#include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp>

namespace msm = boost::msm;
namespace mpl = boost::mpl;
using namespace msm::front;

#include <iostream>

namespace sm
{
    // events
    struct start 
    {
	start()
	{
		std::cout << "event:start " << std::endl;
	}
    };
    struct stop 
    {
	stop()
	{
		std::cout << "event:stop " << std::endl;
	}
    };
    struct pause 
    {
	pause()
	{
		std::cout << "event:pause " << std::endl;
	}
    };
    struct resume 
    {
	resume()
	{
		std::cout << "event:resume " << std::endl;
	}
    };
    struct abort 
    {
	abort()
	{
		std::cout << "event:abort  " << std::endl;
	}
    };

    // Concrete FSM implementation 
    struct player_ : public msm::front::state_machine_def<player_>
    {
        // no need for exception handling or message queue
        typedef int no_exception_thrown;
        typedef int no_message_queue;

        // The list of FSM states
        struct Sleeping : public msm::front::state<> 
        { 
            template <class Event,class FSM>
            void on_entry(Event const&,FSM& ) {std::cout << "entering: state::Sleeping" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "leaving: state::Sleeping" << std::endl;}
        };

        struct Occurring : public msm::front::state<>
        {
            template <class Event,class FSM>
            void on_entry(Event const&,FSM& ) {std::cout << "entering: state::Occurring" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "leaving: state::Occurring" << std::endl;}
        };

        struct Paused : public msm::front::state<>
        {
            template <class Event,class FSM>
            void on_entry(Event const&,FSM& ) {std::cout << "entering: state::Paused" << std::endl;}
            template <class Event,class FSM>
            void on_exit(Event const&,FSM& ) {std::cout << "leaving: state::Paused" << std::endl;}
        };

        // the initial state of the player SM. Must be defined
        typedef Sleeping initial_state;
        // transition actions
        struct starts
        {
            template <class FSM,class EVT,class SourceState,class TargetState>
            void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
            {
		std::cout << "transition::starts" << std::endl;
            }
        };
        struct stops 
        {
            template <class FSM,class EVT,class SourceState,class TargetState>
            void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
            {
		std::cout << "transition::stops " << std::endl;
            }
        };
        struct pauses
        {
            template <class FSM,class EVT,class SourceState,class TargetState>
            void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
            {
		std::cout << "transition::pauses" << std::endl;
            }
        };
        struct resumes
        {
            template <class FSM,class EVT,class SourceState,class TargetState>
            void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
            {
		std::cout << "transition::resumes" << std::endl;
            }
        };
        struct aborts
        {
            template <class FSM,class EVT,class SourceState,class TargetState>
            void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
            {
		std::cout << "transition::aborts" << std::endl;
            }
        };

        struct noop 
        {
            template <class FSM,class EVT,class SourceState,class TargetState>
            void operator()(EVT const& ,FSM&,SourceState& ,TargetState& )
            {
		std::cout << "transition::noop" << std::endl;
            }
        };
        // Transition table for player
        struct transition_table : mpl::vector<
            //    Start       Event        Next        Action                Guard
            //    +-----------+------------+-----------+---------------------+----------------------+
              Row < Sleeping  , start      , Occurring , starts                                   >,
            //  Row < Sleeping  , stop       , Sleeping  , noop                                	  >,
            //  Row < Sleeping  , pause      , Sleeping  , noop                                     >,
            //  Row < Sleeping  , resume     , Sleeping  , noop                                     >,
            //  Row < Sleeping  , abort      , Sleeping  , noop                                     >,
            //    +-----------+------------+-----------+---------------------+----------------------+
            //  Row < Occurring , start      , Occurring , noop		                          >,
              Row < Occurring , stop       , Sleeping  , stops                                    >,
              Row < Occurring , pause      , Paused    , pauses                                   >,
            //  Row < Occurring , resume     , Occurring , noop                                     >,
              Row < Occurring , abort      , Sleeping  , aborts                                   >,
            //    +-----------+------------+-----------+---------------------+----------------------+
            //  Row < Paused    , start      , Paused    , noop                                     >,
              Row < Paused    , stop       , Sleeping  , stops                                    >,
            //  Row < Paused    , pause      , Paused    , noop                                     >,
              Row < Paused    , resume     , Occurring , resumes                                  >,
              Row < Paused    , abort      , Sleeping  , aborts                                   >
            //    +-----------+-------------+---------+---------------------+----------------------+
        > {};

        // Replaces the default no-transition response.
        template <class FSM,class Event>
        void no_transition(Event const& e, FSM&,int state)
        {
            std::cout << "no transition from state " << state
                << " on event " << typeid(e).name() << std::endl;
        }
    };

    typedef msm::back::state_machine<player_> player;

    //
    // Testing utilities.
    //
    static char const* const state_names[] = { "Sleeping", "Occurring", "Paused" };

    void pstate(player const& p)
    {
        std::cout << " -> " << state_names[p.current_state()[0]] << std::endl;
    }
}

int main()
{
    sm::player p;
    p.start();
    p.process_event(sm::start());      
    sm::pstate(p);
    p.process_event(sm::pause()); 
    p.process_event(sm::resume()); 
    p.process_event(sm::stop());  
    sm::pstate(p);
    p.process_event(sm::stop());
    p.process_event(sm::start());
    p.process_event(sm::abort());
    sm::pstate(p);
    return 0;
}

